package com.etone.prodcons;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

public class ProQueue<T> implements Serializable, Runnable{

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private static final int MINSIZE = Integer.MIN_VALUE;
	private static final int MAXSIZE = Integer.MAX_VALUE;
	
	private Boolean opered = false;
	
	private OperFlag operFlag = OperFlag.PUT;
	
	private int size = 10;
	List<T> queue = null;
	
	
	public ProQueue() {
		this.size = 10;
		queue = new ArrayList<T>();
	}
	
	public boolean isFull(){
		return queue.size() >= this.size;
	}
	
	public boolean isEmpty(){
		return queue.size() == 0;
	}
	
	private void setOpered(Boolean oper){
		opered = oper;
		if(isFull()){
			operFlag = OperFlag.TAKE;
		} else if(isEmpty()){
			operFlag = OperFlag.PUT;
		} else{
			operFlag = OperFlag._DEFAULT;
		}
//		synchronized(opered){
//			opered.notify();
//			return opered;
//		}
	}
	
	@SuppressWarnings("unchecked")
	public synchronized boolean put(Object t){
		synchronized(this){
			int startLength = queue.size();
					
			try {
				if(isFull()){
					wait();
					return put(t);
				}
				setOpered(true);
				queue.add((T)t);
System.out.println("==================== queue.size : " + queue.size());
				notify();
				
			} catch (Exception e) {
				e.printStackTrace();
			}
			return queue.size() - startLength >= 1;
		}
	}

	/**
	 * Define the delay time, if exceed this amout, excution will timeout
	 */
	int delay = 1000;
	int times = 10;
	int delayTimes = 0;
	public  T take(){
		T t = null;
		synchronized(this){
			try {
				if (isEmpty()) {
					wait(delay);
					if(delayTimes<times)
						return take();
				} 
				setOpered(true);
				t = queue.remove(0);
System.out.println("-------------------- queue.size : " + queue.size());
				notify();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return t;
	}

	@Override
	public void run() {
		
		synchronized(opered){
			try {
				while(true){
					
					opered.notify();
					opered.wait();
					if(opered){
						
						notifyAll();
						opered = false;
					}
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		
		}
		
	}
}
